#ifndef __INK_PTHREAD_H__
#define __INK_PTHREAD_H__

#include <pthread.h>
#include <errno.h>
#include <time.h>
#include <stdlib.h>

typedef pthread_t 			ink_thread;
typedef pthread_mutex_t 	ink_mutex;
typedef pthread_cond_t		ink_cond;
typedef pthread_key_t 		ink_thread_key;

typedef struct timespec  ink_timestruc;

/**
* 创建一个新的线程
* 参数:启动例程(函数指针) 启动例程所需参数 是否分离线程(join or detached) 线程栈大小 线程栈起始地址
* 返回值: 线程id
* 创建线程失败,将导致程序终止.
* 创建线程失败原因:
*		1.资源不足
*		2.没有权限
*		3.遇到系统设置上限
*		4.attr设置无效.(该函数只能是来自 stack的设置无效)
*	不管是那种失败原因,即使返回EAGAIN,也都不是我们想要的.因此终止程序.
*/
static inline ink_thread
ink_thread_create(void *(*f)(void *), void *a, int detached = 0, size_t stacksize = 0, void *stack = NULL)
{
	ink_thread t;
	int ret;
	pthread_attr_t attr;

	pthread_attr_init(&attr);
	pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);

	if(stacksize) {
		if(stack) {
			pthread_attr_setstack(&attr, stack, stacksize);
		}else{
			pthread_attr_setstacksize(&attr,stacksize);
		}
	}

	if(detached) {
		pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
	}

	ret = pthread_create(&t, &attr, f, a);
	if(ret != 0) {
		abort();
	}
	pthread_attr_destroy(&attr);

	return ret ? (ink_thread)0 : t;
}

/**
* 以阻塞的方式等待线程结束,并获取线程退出状态
* 参数:线程id 用户定义指针,用来获取线程返回值
* ret只需要定义指针即可,不需要申请空间.为NULL时表示不需要返回值,否则用户需要通过free释放ret.
* 返回值:返回errno, 0表示没有错误
*			EDEADLK:多个线程同时调用join来阻塞等待线程结束,造成死锁
*			EINVAL:等待的线程被设置为detached 或者 已经有其他的线程阻塞等待
*			ESRCH:指定id的线程不存在
*/
static inline int
ink_thread_join(ink_thread t, void *ret)
{
	int r = pthread_join(t, &ret);

	if(r == 0)
		return 0;
	return errno;
}


/*
* 获取当前线程的线程id
* the function always success
*/
static inline ink_thread
ink_thread_self()
{
	return (pthread_self());
}

/**
* 取消线程
* 参数: 被取消的线程id
* 返回值: 返回errno,0表示没有错误
*		ESRCH:没有与该id相对应的线程.
*/
static inline int
ink_thread_cancel(ink_thread who)
{
	int ret = pthread_cancel(who);

	if(ret == 0)
		return 0;
	return errno;
}

/**
* 线程主动结束自己
* 通过status可以传递线程的退出状态.其他线程可以通过pthread_join来获取到该内容
**/
static inline void
ink_thread_exit(void *status)
{
	pthread_exit(status);
}


/**
* 初始化化mutex
* the function always success
*/
static inline void
ink_mutex_init(ink_mutex *m)
{
	pthread_mutex_init(m, NULL);
}

/**
*	阻塞上锁,直到上锁成功
*	该函数任何错误都是致命的.它代表着mutex可能未正确初始化.
*   强烈建议,在异步非阻塞编程中,除非必要,否则不使用该函数.
**/
static inline void
ink_mutex_lock(ink_mutex *m)
{
	if(pthread_mutex_lock(m) != 0) {
		abort();
	}
}

/**
* 尝试上锁,不论上锁成功还是失败都会立即返回.
* 在非阻塞异步编程中,除非必要情况,否则都是使用该方式进行上锁.而非阻塞上锁
* 返回值:1表示上锁成功,0表示上锁失败.上锁异常将导致程序退出.
*/
static inline int
ink_mutex_try_lock(ink_mutex *m)
{
	return pthread_mutex_trylock(m) == 0;

}

/**
* 释放锁
* 出错将导致程序终止.
* 锁未正确初始化,或者在当前线程释放其他线程持有的锁.不管是哪一种问题,都不应该在正常的程序中出现
* 建议:在调用try_lock接口之后,需要判断上锁成功再调用release.
**/
static inline void
ink_mutex_release(ink_mutex *m)
{
	if(pthread_mutex_unlock(m) != 0)
		abort();
}

/**
* 销毁锁
* 返回1表示销毁锁成功,返回0表示销毁失败(锁正在被持有,或者多次调用了release)
**/
static inline int
ink_mutex_destroy(ink_mutex *m)
{
	return pthread_mutex_destroy(m) != 0;
}

/**
* 初始化condition
* 出错将导致程序终止
*/
static inline void
ink_cond_init(ink_cond *c)
{
	if(pthread_cond_init(c, NULL) != 0)
		abort();
}

/**
* 销毁condition
* 当销毁一个正在阻塞的condition时将导致程序终止.
**/
static inline void
ink_cond_destroy(ink_cond *c)
{
	if(pthread_cond_destroy(c) != 0)
		abort();
}

/**
* condition wait  
**/
inline void
ink_cond_wait(ink_cond *c, ink_mutex *m)
{
	if(pthread_cond_wait(c, m) != 0)
		abort();
}

/**
* condition time wait
*/
static inline void
ink_cond_time_wait(ink_cond *c, ink_mutex *m, ink_timestruc *t)
{
	int err;

	while(EINTR == (err = pthread_cond_timedwait(c, m, t)))
		;
	if(err != ETIMEDOUT && err != 0)
		abort();
}

/**
* condition signal
*/
static inline void
ink_cond_signal(ink_cond *c)
{
	if(pthread_cond_signal(c) != 0)
		abort();
}

/**
* condition broadcast
**/
static inline void
ink_cond_broadcast(ink_cond *c)
{
	if(pthread_cond_broadcast(c) != 0)
		abort();
}


/*******************************************
***			线程存储相关				 ***
*******************************************/

/**
* 创建pthread_key
* 参数:要初始化的pthread_key_t, 清理函数
*	清理函数可以为NULL,在销毁该key时将调用默认的清理函数.
*/
static inline void
ink_thread_key_create(ink_thread_key *key, void (*destr_fun)(void *value))
{
	if(pthread_key_create(key, destr_fun) != 0)
		abort();	
}

/**
* 销毁pthread_key
* 销毁一个不存在的key时,将导致程序终止
*/
static inline void
ink_thread_key_delete(ink_thread_key key)
{
	if(pthread_key_delete(key) != 0)
		abort();
}

/**
* 将value保存到线程私有数据空间
**/
static inline void
ink_thread_setspecific(ink_thread_key key, void *value)
{
	if(pthread_setspecific(key, value) != 0)
		abort();
}

/**
* 根据Key获取线程私有数据空间上存储的value
* 如果出错则返回NULL.返回NULL时,意味着该key是无效的.
*/
static inline void *
ink_thread_getspecific(ink_thread_key key)
{
	return pthread_getspecific(key);
}

/*set thread name*/
static inline void
ink_set_thread_name(const char *name)
{
	pthread_setname_np(pthread_self(), name);
}

#endif
